/**
* Oxide
*
* Copyright (c) 2011 Dinosaur Kick Pty Ltd, All rights reserved.
*
* This source code is made available under the "Modified BSD" licensing arrangement.
* See license.txt for details.
*/
// ----------------------------------------------------------------------------
#include <string>
#include "ast_fwd.hpp"
// ----------------------------------------------------------------------------
#ifndef O2_AST_VISITOR_INC
#define O2_AST_VISITOR_INC
namespace o2 {
namespace ast {
// ----------------------------------------------------------------------------

#define O2_AST_VISITOR_FUNC_VOID_PROTO(s, data, name) \
	virtual void visit_interface(const BOOST_PP_CAT(basic_, name)<StringT>& host) = 0;

#define O2_AST_VISITOR_FUNC_VOID_ITER(s, data, name) \
	virtual void visit_interface(const BOOST_PP_CAT(basic_, name)<StringT>& host) \
		{ static_cast<DerivedT*>(this)->visit(host); }

#define O2_AST_VISITOR_FUNC_NON_VOID_ITER(s, data, name) \
	virtual void visit_interface(const BOOST_PP_CAT(basic_, name)<StringT>& host) \
		{ m_value = static_cast<DerivedT*>(this)->visit(host); }

// ----------------------------------------------------------------------------

template <typename StringT>
class basic_visitor_base
{
	public:
		O2_AST_TYPEDEFS(StringT);
		BOOST_PP_SEQ_FOR_EACH(O2_AST_VISITOR_FUNC_VOID_PROTO, _, O2_AST_CONCRETE_NODE_TYPES);
};

// ----------------------------------------------------------------------------

template <typename DerivedT, typename StringT, typename ReturnT>
class basic_visitor
	: public basic_visitor_base<StringT>
{
	public:
		O2_AST_TYPEDEFS(StringT);
		BOOST_PP_SEQ_FOR_EACH(O2_AST_VISITOR_FUNC_NON_VOID_ITER, _, O2_AST_CONCRETE_NODE_TYPES);

		template <typename HostT>
		const ReturnT& apply(const HostT& host)
			{ host.accept(*this); return m_value; }
	
		template <typename HostT>
		const ReturnT& operator() (const HostT& host)
			{ return apply(host); }

	private:
		mutable ReturnT m_value;
};

// ----------------------------------------------------------------------------

template <typename DerivedT, typename StringT>
class basic_visitor<StringT, DerivedT, void>
	: public basic_visitor_base<StringT>
{
	public:
		O2_AST_TYPEDEFS(StringT);
		BOOST_PP_SEQ_FOR_EACH(O2_AST_VISITOR_FUNC_VOID_ITER, _, O2_AST_CONCRETE_NODE_TYPES);
	
		template <typename HostT>
		void apply(const HostT& host)
			{ host.accept(*this); }
	
		template <typename HostT>
		void operator() (const HostT& host)
			{ apply(host); }
};

// ----------------------------------------------------------------------------

typedef basic_visitor_base<std::string> visitor;
typedef basic_visitor_base<std::wstring> wvisitor;

// ----------------------------------------------------------------------------
} // namespace ast
} // namespace o2
#endif // O2_AST_VISITOR_INC
// ----------------------------------------------------------------------------
